use poker_lib::{PokerCard, Suit};

use crate::{card_weight::CardWeight, turn::TurnHandPileState};

pub struct Utils;
impl Utils {
    pub fn get_next_player_id(player_id: usize) -> usize {
        (player_id + 1) % 4
    }

    pub fn get_prev_player_id(player_id: usize) -> usize {
        if player_id == 0 {
            4 - 1
        } else {
            player_id - 1
        }
    }
    pub fn get_partner_player_id(player_id: usize) -> usize {
        (player_id + 2) % 4
    }
    pub fn check_pile_has_rank(pile: &Vec<PokerCard>, rank: i16) -> bool {
        pile.iter().any(|&card| card.get_number() == rank)
    }
    pub fn check_pile_has_card(pile: &Vec<PokerCard>, target: &PokerCard) -> bool {
        pile.iter().any(|&card| {
            card.get_number() == target.get_number() && card.get_suit() == target.get_suit()
        })
    }
    pub fn get_ak_num(pile: &Vec<PokerCard>) -> i16 {
        let mut num: i16 = 0;
        for card in pile {
            let (_t, n) = card.get_suit_num();
            if n == 1 || n == 13 {
                num += 1;
            }
        }
        num
    }
    pub fn has_suit_poker_in_other_voided_suit_list(
        cards: &Vec<PokerCard>,
        voided_list: &Vec<Suit>,
    ) -> bool {
        for card in cards.iter() {
            if voided_list.contains(&card.suit) {
                return true;
            }
        }
        false
    }
    ///当历史记牌器或者自己手里有比伙伴大的牌 或者已经出的牌有比伙伴大的牌 return false
    pub fn is_partner_win_now_turn(
        partner_card: &PokerCard,
        hand_cards_same_with_win_suit: &Vec<PokerCard>,
        turn_out_suit_cards: &Vec<PokerCard>,
        history_suit_piles: &Vec<PokerCard>,
    ) -> bool {
        //判定下花色不同的情况
        if turn_out_suit_cards.len() > 0 {
            let win_card = turn_out_suit_cards.first().unwrap();
            if win_card.is_trump_card() && !partner_card.is_trump_card() {
                return false;
            }
        }
        for i in (partner_card.get_number() as i16 + 1)..=13 {
            if !(Utils::check_pile_has_rank(hand_cards_same_with_win_suit, i)
                || Utils::check_pile_has_rank(history_suit_piles, i))
                || Utils::check_pile_has_rank(turn_out_suit_cards, i)
            {
                return false;
            }
        }
        true
    }
    pub fn get_cards_by_suit(cards: &Vec<PokerCard>, suit: u8) -> Vec<PokerCard> {
        cards
            .iter()
            .filter(|&card| card.get_suit() == suit)
            .cloned()
            .collect()
    }
    ///判断card 是否是目前最大的牌
    pub fn is_card_biggest_now(
        card: &PokerCard,
        win_suit_cards: &Vec<PokerCard>,
        history_suit_piles: &Vec<PokerCard>,
    ) -> bool {
        let mut result = true;
        for i in (card.get_number() as i16 + 1)..=14 {
            if !Utils::check_pile_has_rank(history_suit_piles, i)
                || Utils::check_pile_has_rank(win_suit_cards, i)
            {
                result = false;
                break;
            }
        }
        result
    }
    //计算牌值最小 并且张数最多的牌
    pub fn compute_lower_rank_and_most_card_num(
        _hand_pile: &TurnHandPileState,
        _card_weights: &mut Vec<CardWeight>,
    ) -> bool {
        let mut has_add = false;
        for item in _hand_pile.playable_pile.iter() {
            if !item.is_trump_card()
                || _hand_pile.playable_pile.len() == _hand_pile.spades_pile.len()
            {
                let pile = &_hand_pile.pile_suit_group.get_suit_pocker_cards(item.suit);
                let card_x = 14 - item.get_number() as i16;
                CardWeight::add_card_x(card_x as i16, item, _card_weights);
                let card_y = pile.len() as i16;
                CardWeight::add_card_y(card_y as i16, item, _card_weights);
                has_add = true;
            }
        }
        has_add
    }
    //计算牌值最小 并且张数最少的牌
    pub fn compute_lower_rank_and_fewer_card_num(
        _hand_pile: &TurnHandPileState,
        _card_weights: &mut Vec<CardWeight>,
    ) -> bool {
        let mut has_add = false;
        for item in _hand_pile.playable_pile.iter() {
            if !item.is_trump_card()
                || _hand_pile.playable_pile.len() == _hand_pile.spades_pile.len()
            {
                let pile = &_hand_pile.pile_suit_group.get_suit_pocker_cards(item.suit);
                let card_x = 14 - item.get_number() as i16;
                CardWeight::add_card_x(card_x as i16, item, _card_weights);
                let card_y = 13 - pile.len() as i16;
                CardWeight::add_card_y(card_y as i16, item, _card_weights);
                has_add = true;
            }
        }
        has_add
    }
    //计算张数最少并且牌值最小的牌
    pub fn compute_fewer_card_num_and_lower_rank(
        _hand_pile: &TurnHandPileState,
        _card_weights: &mut Vec<CardWeight>,
    ) -> bool {
        let mut has_add = false;
        for item in _hand_pile.playable_pile.iter() {
            if !item.is_trump_card()
                || _hand_pile.playable_pile.len() == _hand_pile.spades_pile.len()
            {
                let pile = &_hand_pile.pile_suit_group.get_suit_pocker_cards(item.suit);
                let card_x = 13 - pile.len() as i16;
                CardWeight::add_card_x(card_x as i16, item, _card_weights);
                let card_y = 14 - item.get_number() as i16;
                CardWeight::add_card_y(card_y as i16, item, _card_weights);
                has_add = true;
            }
        }
        has_add
    }
    pub fn get_greater_card_pile(card: &PokerCard, pile: &Vec<PokerCard>) -> Vec<PokerCard> {
        let mut result = Vec::new();
        for item in pile.iter() {
            if item.get_number() > card.get_number() {
                result.push(*item);
            }
        }
        result
    }
    pub fn get_lowest_rank_card(pile: &Vec<PokerCard>) -> Option<&PokerCard> {
        if pile.is_empty() {
            return None;
        }
        let mut result = pile.last().unwrap();
        for item in pile.iter() {
            if item.get_number() < result.get_number() {
                result = item;
            }
        }
        Some(result)
    }
    pub fn get_highest_rank_from_pile(pile: &Vec<PokerCard>) -> Option<&PokerCard> {
        if pile.is_empty() {
            return None;
        }
        let mut result = pile.last().unwrap();
        for item in pile.iter() {
            if item.get_number() > result.get_number() {
                result = item;
            }
        }
        Some(result)
    }
    pub fn get_lowest_but_greater_than_win_card(
        card: &PokerCard,
        pile: &Vec<PokerCard>,
    ) -> Option<PokerCard> {
        match Self::get_highest_rank_from_pile(pile) {
            Some(mut card2) => {
                if card2.get_number() > card.get_number() {
                    for item in pile.iter() {
                        if item.get_number() < card2.get_number()
                            && item.get_number() > card.get_number()
                        {
                            card2 = item;
                        }
                    }
                    return Some(*card2);
                }
            }
            None => {}
        }
        None
    }
    pub fn get_highest_but_less_than_win_card(
        card: &PokerCard,
        pile: &Vec<PokerCard>,
    ) -> Option<PokerCard> {
        //从pile里找到比card.get_number()小的最大的牌
        if let Some(mut value) = Self::get_lowest_rank_card(pile) {
            if value.get_number() < card.get_number() {
                for item in pile.iter() {
                    if item.get_number() > value.get_number()
                        && item.get_number() < card.get_number()
                    {
                        value = item;
                    }
                }
                return Some(*value);
            }
            return None;
        }
        None
    }
    pub fn get_greeter_rank_but_hidden_card_nums(
        card: &PokerCard,
        hand_pile: &Vec<PokerCard>,
        history_pile: &Vec<PokerCard>,
    ) -> usize {
        let mut num = 0;
        for i in (card.get_number() as usize + 1)..=14 {
            if !Utils::check_pile_has_rank(&history_pile, i as i16)
                && !Utils::check_pile_has_rank(&hand_pile, i as i16)
            {
                num += 1;
            }
        }
        num
    }
    pub fn get_team_by_player_id(player_id: usize, mode: i16) -> usize {
        if mode == 1 {
            return if player_id == 0 || player_id == 2 {
                0
            } else {
                1
            };
        } else if mode == 2 {
            return player_id;
        }
        return player_id;
    }
}
